#include "string_utilities.h"

using std::cerr;
using std::endl;
using std::ios;
using std::string;
using std::vector;
using std::stringstream;

const std::string delim = " \t\r\n";


string trim_right(const string & s, const string & t)
{
    string d(s);
    string::size_type i(d.find_last_not_of(t));
    if (i == string::npos)
        return "";
    else
        return d.erase(d.find_last_not_of(t) + 1);
}

string trim_left(const string & s, const string & t)
{
    string d(s);
    return d.erase(0, s.find_first_not_of(t));
}

string trim(const string & s, const string & t)
{
    string d(s);
    return trim_left(trim_right(d, t), t);
}

unsigned long split(const std::string& s, std::vector<std::string>& tokens,  
        const std::string& delim, bool remove_empty)
{
    std::ostringstream word;
    for (size_t n = 0; n < s.size(); ++n)
    {
        if (std::string::npos == delim.find(s[n]))
            word << s[n];
        else
        {
            if (!word.str().empty() || !remove_empty)
                tokens.push_back(word.str());
            word.str("");
        }
    }
    if (!word.str().empty() || !remove_empty)
        tokens.push_back(word.str());
    return tokens.size();
}

bool isDouble(const std::string& s)
{
    size_t n = s.size();
    bool b = true;

    for (size_t i = 0; i < (n - 1); i++)
    {
        if (isDigit(s[i]) == false && (s[i] != '.') && (s[i] != ','))
            return false;
    }
    if (((s[n - 1] == '\n') || (s[n - 1] == '\r')) && (n > 1))
        return b;
    else if (isDigit(s[n - 1]) == false)
        b = false;
    return b;
}

class Exc
{
private:
  std::string mess;
public:
  Exc(std::string m) : mess(m) { }
  void print(void) { cerr << mess << std::endl; }
};


double str2double(const string& s)
{
    if (isDouble(s) == false)
    {
        cerr << __FILE__ << ": str2double() input string (" << s << ") is not a number " <<
                "return 0" << endl;
        return 0;
    }


    double d;
    stringstream ss;
    ss << s;
    ss >> d;
    if ((ss.rdstate() == ios::failbit) ||
            (ss.rdstate() == ios::badbit))
    {
        cerr << __FILE__ << ": str2double() io error occurred, " <<
                "return 0" << endl;
        return 0;
    }
   std::string t;
   ss >> std::skipws >> t;
   if(t!="")
     {
       cerr << __FILE__ << ": str2double() input string is not a number " <<
         "return 0" << endl;
       throw Exc("bad input");
       return 0;
     } 

    return d;
}

int str2int(const string& s)
{
    if (isInteger(s) == false)
    {
        cerr << __FILE__ << ": str2int() input string (" << s << ") is not a number " <<
                "return 0" << endl;
        return 0;
    }
    int x;
    stringstream ss;
    ss << s;
    ss >> x;
    if ((ss.rdstate() == ios::failbit) ||
            (ss.rdstate() == ios::badbit))
    {
        cerr << __FILE__ << ": str2int() io error occurred, return 0" << endl;
        return 0;
    }
    return x;
}

bool startsWith(const string& s, const string& t)
{
    if (s.size() < t.size())
        return false;
    size_t n = t.size();
    for (size_t i = 0; i < n; i++)
    {
        if (s[i] != t[i])
            return false;
    }
    return true;
}

std::string double2str(const double d)
{
    stringstream ss;
    ss << d;
    if ((ss.rdstate() == ios::failbit) ||
            (ss.rdstate() == ios::badbit))
    {
        cerr << __FILE__ << ": double2str() io error occurred, returning " <<
                "an empty string" << endl;
        return "";
    }
    return ss.str();
}

std::string int2str(const int x)
{
    stringstream ss;
    ss << x;
    if ((ss.rdstate() == ios::failbit) ||
            (ss.rdstate() == ios::badbit))
    {
        cerr << __FILE__ << ": int2str() io error occurred, returning " <<
                "an empty string" << endl;
        return "";
    }
    return ss.str();
}

std::string long2str(const long x)
{
    stringstream ss;
    ss << x;
    if ((ss.rdstate() == ios::failbit) ||
            (ss.rdstate() == ios::badbit))
    {
        cerr << __FILE__ << ": long2str() io error occurred, returning " <<
                "an empty string" << endl;
        return "";
    }
    return ss.str();
}

bool isDigit(const char c)
{
    if (c == '0' || c == '1' || c == '2' || c == '3' || c == '4'
            || c == '5' || c == '6' || c == '7' || c == '8' || c == '9')
        return true;
    else
        return false;
}

bool isInteger(const std::string& s)
{
    size_t n = s.size();
    bool b = true;

    for (size_t i = 0; i < (n - 1); i++)
    {
        if (isDigit(s[i]) == false)
            return false;
    }
    if (((s[n - 1] == '\n') || (s[n - 1] == '\r')) && (n > 1))
        return b;
    else if (isDigit(s[n - 1]) == false)
        b = false;
    return b;
}

//bool isDouble(const std::string& s)
//{
//    size_t n = s.size();
//    bool b = true;
//
//    for (size_t i = 0; i < (n - 1); i++)
//    {
//        if (isDigit(s[i]) == false && (s[i] != '.') && (s[i] != ','))
//            return false;
//    }
//    if (((s[n - 1] == '\n') || (s[n - 1] == '\r')) && (n > 1))
//        return b;
//    else if (isDigit(s[n - 1]) == false)
//        b = false;
//    return b;
//}